package com.wstuo.common.sla.service;

import org.apache.log4j.Logger;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import com.wstuo.common.rules.dao.IRuleDAO;
import com.wstuo.common.rules.dao.IRulePackageDAO;
import com.wstuo.common.rules.entity.Rule;
import com.wstuo.common.rules.entity.RuleAction;
import com.wstuo.common.rules.entity.RuleConstraint;
import com.wstuo.common.rules.entity.RulePackage;
import com.wstuo.common.rules.parser.ProcreationDrlFiles;
import com.wstuo.common.rules.parser.RuleParser;
import com.wstuo.common.rules.service.IRuleService;
import com.wstuo.common.security.utils.FileEncodeUtils;
import com.wstuo.common.sla.dao.ISLAContractDAO;
import com.wstuo.common.sla.dao.ISLARuleDAO;
import com.wstuo.common.sla.dto.SLARuleDTO;
import com.wstuo.common.sla.dto.SLARuleQueryDTO;
import com.wstuo.common.sla.entity.SLAContract;
import com.wstuo.common.sla.entity.SLARule;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.exception.ApplicationException;
import com.wstuo.common.file.csv.CSVReader;
import com.wstuo.common.file.csv.CSVWriter;
import com.wstuo.common.util.StringUtils;
import com.wstuo.common.util.TimeUtils;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

/**
 * SLA规则物业类.
 * @author QXY
 */
public class SLARuleService implements ISLARuleService {
    /**
     * Logger for this class
     */
    private static final Logger LOGGER = Logger.getLogger(SLARuleService.class);

	@Autowired
    private ISLARuleDAO slaRuleDAO;
	@Autowired
	private IRuleDAO ruleDAO;
	@Autowired
	private IRuleService ruleService;
	@Autowired
    private ISLAContractDAO slaContractDAO;
	private ProcreationDrlFiles procreationDrlFiles=new ProcreationDrlFiles();
	
	@Autowired
    private IRulePackageDAO rulePackageDAO;
	
	private RuleParser ruleParser = new RuleParser();

	/**
	 * SLA Entity to dto
	 * @param entity
	 * @param dto
	 */
    private void slaEntity2dto(SLARule entity, SLARuleDTO dto) {
    	if(entity.getRespondTime()!=0){
    		dto.setShowRespondTime(TimeUtils.second2DHM(entity.getRespondTime()));
    	}
    	if(entity.getFinishTime()!=0){
    		dto.setShowFinishTime(TimeUtils.second2DHM(entity.getFinishTime()));
    	}
    	if(entity.getSlaContract()!=null){
    		dto.setContractName(entity.getSlaContractName());
    		dto.setCompanyName(entity.getSlaContractServiceOrgName());
    		dto.setBeginTime(entity.getSlaContractBeginTime());
    		dto.setEndTime(entity.getSlaContractEndTime());
    	}
        try {

            BeanUtils.copyProperties(dto, entity);
        } catch (Exception ex) {
            throw new ApplicationException(ex);
        }
    }
    
	/**
	 * 分页查找数据.
	 * @param qdto 查询DTO
	 * @param start 开始数据行
	 * @param limit 每页数据条数
	 * @return PageDTO 分页数据
	 */
    @SuppressWarnings("unchecked")
    @Transactional
	public PageDTO findPagerByContractNo(SLARuleQueryDTO qdto, String sidx, String sord,int start,
        int limit) {
        PageDTO p = slaRuleDAO.findPager(qdto,sidx,sord,start, limit);
        List<SLARule> entities = p.getData();
        List<SLARuleDTO> dtos = new ArrayList<SLARuleDTO>(entities.size());
        for (SLARule entity : entities) {
            SLARuleDTO dto = new SLARuleDTO();
            slaEntity2dto(entity, dto);
            dtos.add(dto);
        }
        p.setData(dtos);
        return p;
    }
    
    /**
     * 查询所有sla规则
     * @param qdto
     */
    @Transactional
    public List<SLARuleDTO> findAll(SLARuleQueryDTO qdto){
    	List<SLARule> entities = slaRuleDAO.findSLARule(qdto);
        List<SLARuleDTO> dtos = new ArrayList<SLARuleDTO>(entities.size());
        for (SLARule entity : entities) {
            SLARuleDTO dto = new SLARuleDTO();
            slaEntity2dto(entity, dto);
            dtos.add(dto);
        }
        return dtos;
    }

    /**
     * 根据编号查找SLA规则.
     * @param no SLA规则编号
     * @return SLARule
     */
    @Transactional
    public SLARule findSLARuleById(Long no) {
    	SLARule slaRule = slaRuleDAO.findById(no);
    	if(slaRule!=null){
	        if(slaRule.getActions()!=null){
	        	 slaRule.getActions().size();
	        }
	        if(slaRule.getCondition()!=null){
	        	slaRule.getCondition().getConstraints().size();
	        }
    	}
    	return slaRule;
        
    }

    /**
     * 修改SLA规则
     * @return SLARule
     */
	@Transactional
    public SLARule mergeRuleEntity(SLARule slaRule) {

    	SLARule rule=slaRuleDAO.findById(slaRule.getRuleNo());//取得要修改的SLARule
    	
    	modifyPropertyValue(slaRule,rule);
    	
    	//条件集合
    	if(slaRule.getCondition().getConstraints()!=null && slaRule.getCondition().getConstraints().size()>0){
    		rule.getCondition().setConstraints(slaRule.getCondition().getConstraints());
    	}else{
    		rule.getCondition().setConstraints(new ArrayList());
    	}
    	//动作集合（1个）(由于SLA规则匹配后的动作就是将当前规则返回给请求，所以动作集就是修改匹配规则名（默认）；但其他的规则就可以有多个动作集的;)
    	//动作集默认是修改匹配规则，所以GivenValue的值就是规则名
    	if(rule.getActions()!=null && rule.getActions().size()>0){
    		rule.getActions().get(0).setGivenValue(slaRule.getRuleName());
    		rule.getActions().get(0).setGivenName(slaRule.getRuleName());
    	}else{//设置新的动作
    		List<RuleAction> actions=new ArrayList<RuleAction>(1);
    		RuleAction action=new RuleAction();
    		action.setGivenValue(slaRule.getRuleName());
    		action.setGivenName(slaRule.getRuleName());
    		actions.add(action);
    		rule.setActions(actions);
    	}
        rule = slaRuleDAO.merge(rule);
        procreationDrlFiles.printDrlFiles(rule);
        return rule;	
    }

    private void modifyPropertyValue(SLARule slaRule,SLARule rule){
    	//修改基本信息
    	rule.setRuleName(slaRule.getRuleName());
    	rule.setSalience(slaRule.getSalience());
 
    	//响应时间
    	rule.setRday(slaRule.getRday());
    	rule.setRhour(slaRule.getRhour());
    	rule.setRminute(slaRule.getRminute());
    	
    	//完成时间
    	rule.setFday(slaRule.getFday());
    	rule.setFhour(slaRule.getFhour());
    	rule.setFminute(slaRule.getFminute());
    	
    	//响应完成率
    	rule.setResponseRate(slaRule.getResponseRate());
    	rule.setCompleteRate(slaRule.getCompleteRate());
    	
    	//计算方式
    	rule.setIncludeHoliday(slaRule.getIncludeHoliday());
    }
    
    /**
     * 删除SLA规则.
     * @param no 
     */
    @Transactional
    public void removeRule(Long no) {

    	//查到所属的SLA
		SLARule rule = slaRuleDAO.findById(no);
		SLAContract slaContract = rule.getSlaContract();
		RulePackage rulePackage = slaContract.getRulePackage();
		rulePackage.getRules().remove(rule);
		slaRuleDAO.delete(rule);
		procreationDrlFiles.printDrlFiles(rulePackage);        
        
    }

    /**
     * 批量删除SLA规则.
     * @param nos SLA规则编号集合
     */
    @Transactional
    public void removeRules(Long[] nos) {

    	if(nos!=null && nos.length>0){
    		//查到所属的SLA
    		List<SLARule> rules = slaRuleDAO.findByIds(nos);
    		SLARule slaRuleEntity = rules.get(0);
    		SLAContract slaContract = slaRuleEntity.getSlaContract();
    		RulePackage rulePackage = slaContract.getRulePackage();
    		rulePackage.getRules().removeAll(rules);
    		slaRuleDAO.deleteByIds(nos);
    		procreationDrlFiles.printDrlFiles(rulePackage);
    	}
    }

	/**
	 * 添加SLA规则
	 * @param slaRule
	 */
    @Transactional
    public void saveRuleEntity(SLARule slaRule) {
        if (slaRule.getSlaContractNo()!=null) {
            SLAContract contract = slaContractDAO.findById(slaRule.getSlaContractNo());
            slaRule.setSlaContract(contract);
            slaRule.setRulePackage(contract.getRulePackage());
            //add mars
            RulePackage rulePackage=rulePackageDAO.findById(contract.getRulePackageNo());
            if(rulePackage.getRules()!=null){
            	rulePackage.getRules().add(slaRule);
            }else{
            	List<Rule> rules=new ArrayList<Rule>();
            	rules.add(slaRule);
            	rulePackage.setRules(rules);
            }
        }
        if (slaRule.getCondition() != null) {
            for (RuleConstraint constraint : slaRule.getConstraints()) {
                constraint.setPattern(slaRule.getCondition());
            }
        }
        if(slaRule.getActions()!=null && slaRule.getActions().size()>0){
        	for(RuleAction act:slaRule.getActions()){
        		act.setRule(slaRule);
        	}
        }
        slaRuleDAO.save(slaRule);
        procreationDrlFiles.printDrlFiles(slaRule);
    }
    
    
    
    
    /**
     * 导出CSV.
     * @param qdto SLAContractQueryDTO
     */
    @Transactional
    public InputStream exportSLARule(SLARuleQueryDTO qdto){
    	//LanguageContent lc=LanguageContent.getInstance();
    	List<String[]> data = new ArrayList<String[]>();
		data.add(new String[]{
		            "ruleName",
		            "rday",
		            "rhour",
		            "rminute",
		            "fday",
		            "fhour",
		            "fminute",
		            "responseRate",
		            "completeRate",
		            "includeHoliday",
		            "rulePackageNo",
		            "contractNo"});//加入表头
		
		PageDTO p = slaRuleDAO.findPager(qdto,null,null, 0, CSVWriter.EXPORT_SIZE);

		@SuppressWarnings("unchecked")
		List<SLARule> entities = (List<SLARule>) p.getData();
		String rulePackageNo="";
		
	    for(SLARule sl:entities){
	    	if(sl.getRulePackage()!=null && sl.getRulePackage().getRulePackageNo()!=null){
	    		rulePackageNo=sl.getRulePackage().getRulePackageNo()+"";
	    	}else{
	    		rulePackageNo="";
	    	}
	    	
	    	data.add(new String[]{
	    			
	    			sl.getRuleName(),
	    			sl.getRday()+"",
	    			sl.getRhour()+"",
	    			sl.getRminute()+"",
	    			sl.getFday()+"",
	    			sl.getFday()+"",
	    			sl.getFminute()+"",
	    			sl.getResponseRate()+"",
	    			sl.getCompleteRate()+"",
	    			sl.getIncludeHoliday()+"",
	    			rulePackageNo,
	    			""
					});
	    }
	    
		StringWriter sw = new StringWriter();
        CSVWriter csvw = new CSVWriter(sw);
        csvw.writeAll(data);
        ByteArrayInputStream stream = new ByteArrayInputStream(sw.getBuffer().toString().getBytes());
        return stream;
    	
    }
    
    /**
     * 导入CSV.
     * @param importFilePath
     * @return String
     */ 
    @Transactional
    public String importSLARule(String importFilePath){
    	
    	try {
			String fileEncode = FileEncodeUtils.getFileEncode(new File(importFilePath));
			Reader rd = new InputStreamReader(new FileInputStream(importFilePath),fileEncode);//以字节流方式读取数据
			CSVReader reader=new CSVReader(rd);
			String [] line=null;

			Boolean includeHoliday=true;
			while((line=reader.readNext())!=null){
				
				SLARule sl=new SLARule();
				sl.setRuleName(line[0]);
				//响应时间
				sl.setRday(Integer.parseInt(line[1]));
				sl.setRhour(Integer.parseInt(line[2]));
				sl.setRminute(Integer.parseInt(line[3]));
				//完成时间
				sl.setFday(Integer.parseInt(line[4]));
				sl.setFhour(Integer.parseInt(line[5]));
				sl.setFminute(Integer.parseInt(line[6]));
				//响应率
				sl.setResponseRate(Double.parseDouble(line[7]));
				//完成率
				sl.setCompleteRate(Double.parseDouble(line[8]));
				//计算方式
				
				if(line[9].equals("false")){
					includeHoliday=false;
				}else{
					includeHoliday=true;
				}
				sl.setIncludeHoliday(includeHoliday);
				//所属包
				if(StringUtils.hasText(line[10])){
					sl.setRulePackage(rulePackageDAO.findById(Long.parseLong(line[10])));
				}else if(StringUtils.hasText(line[11])){
					SLAContract sc=slaContractDAO.findById(Long.parseLong(line[11]));
					if(sc!=null){
						sl.setSlaContract(sc);
						sl.setRulePackage(sc.getRulePackage());
					}
				}
				slaRuleDAO.save(sl);
			}
			return "success";

    	} catch (FileNotFoundException ex) {
    		
			throw new ApplicationException("ERROR_CSV_FILE_NOT_EXISTS\n"+ex,ex);
		}
		catch (IOException ex) {
			
			throw new ApplicationException("ERROR_CSV_FILE_IO\n"+ex,ex);
		}
		
    }
    
    /**
     * 读取规则文件
     * @param drlFilePath
     * @param slaNo
     * @return rulePackageNo 
     */
    @Transactional
    public String importSLARule_drl(String drlFilePath,Long slaNo){
        String result = null;
    	try {
    		//根据规则内容解析成RulePackage
			RulePackage temp=ruleParser.parser(ruleService.readDrlFile(drlFilePath));//临时
			List<Rule> existsRules=slaContractDAO.findById(slaNo).getRulePackage().getRules();//获取规则包的规则列表
			if(temp.getRules()!=null && temp.getRules().size()>0){
				for(Rule rl:temp.getRules()){
					for(Rule rlExists:existsRules){
						if(rlExists.getRuleName().equals(rl.getRuleName())){
							rlExists.setCondition(rl.getCondition());
							//设置动作，默认1
							List<RuleAction> actions=new ArrayList<RuleAction>();
							RuleAction action=new RuleAction();
							action.setPropertyName("matchRuleName");
							action.setGivenValue(rlExists.getRuleName());
							action.setRule(rlExists);
							actions.add(action);
							rlExists.setActions(actions);
							ruleDAO.merge(rlExists);
						}
					}
				}
			}
			result = "success";
		} catch (Exception e) {
		    LOGGER.error(e);
		    result = "fall";
		}
    	return result;
    }
    
    /**
     * 判断SLA名称是否已存在
     * @param slaName
     * @return boolean
     */
    public boolean slaNameExist(String slaName){
    	SLARule sla = slaRuleDAO.findUniqueBy("ruleName", slaName);
    	return (sla != null);
    }
    
    /**
     * 根据SLA编号查询SLA
     * @param slaRuleNo
     * @return SLARuleDTO
     */
    @Transactional
    public SLARuleDTO findBySlaNo(Long slaRuleNo){
    	SLARule sla = slaRuleDAO.findUniqueBy("ruleNo", slaRuleNo);
    	SLARuleDTO dto=new SLARuleDTO();
    	slaEntity2dto(sla, dto);
    	return dto;
    }
    
}